#!/usr/bin/perl -w

use Time::HiRes;
use strict;

my $MAX=10;
my $size=10;
my $WIDTH=(2*$MAX)+1;
my $FG="X";
my $BG=" ";
my $INTERVAL=100000;

my @disks=();
for ( my $disk=0; $disk<$MAX+1; $disk++ ) {
  my $st=int($WIDTH/2)-$disk;
  my $en=int($WIDTH/2)+$disk;
  for ( my $index=0; $index<$WIDTH; $index++ ) {
    $disks[$disk] .= $index > $st && $index < $en ? $FG : $BG;
  }
}

sub print_pegs {
  my ( $pegs ) = @_;
  system("clear");
  for ( my $tier = $MAX; $tier>-1; $tier-- ) {
    foreach my $peg ( @$pegs ) {
      print $disks[ scalar(@$peg) > $tier ? @$peg[$tier] : 0 ];
    }
    print "\n";
  }
  Time::HiRes::usleep($INTERVAL);
}

sub hanoi {
  my ($n, $pegs, $f, $t, $u ) = @_;
  if ( $n == 1 ) {
    push( @{@$pegs[$t]}, pop(@{@$pegs[$f]}));
    print_pegs( $pegs );
  } else {
    hanoi( $n-1, $pegs, $f, $u, $t );
    hanoi( 1, $pegs, $f, $t, $u );
    hanoi( $n-1, $pegs, $u, $t, $f );
  }
}

my @pegs = ( [reverse(1..$size)], [], [] );
print_pegs( \@pegs );
while ( 1 ) {
  sleep(1);
  hanoi( scalar(@{$pegs[0]}), \@pegs, 0, 1, 2 );
  sleep(1);
  hanoi( scalar(@{$pegs[1]}), \@pegs, 1, 2, 0 );
  sleep(1);
  hanoi( scalar(@{$pegs[2]}), \@pegs, 2, 0, 1 );
}
